package org.csu.softwaremetrics_demo.controller;

import org.csu.softwaremetrics_demo.entity.common.CKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.common.LKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.common.TraditionMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.result.Result;
import org.csu.softwaremetrics_demo.entity.result.impl.CKMetricResult;
import org.csu.softwaremetrics_demo.entity.result.impl.LKMetricResult;
import org.csu.softwaremetrics_demo.entity.result.impl.TraditionMetricResult;
import org.csu.softwaremetrics_demo.service.impl.diagram.ClassDiagramMetricService;
import org.csu.softwaremetrics_demo.service.impl.diagram.UserCaseDiagramMetricService;
import org.csu.softwaremetrics_demo.service.impl.java.CKService;
import org.csu.softwaremetrics_demo.service.impl.java.LKService;
import org.csu.softwaremetrics_demo.service.impl.java.TraditionMetricService;
import org.csu.softwaremetrics_demo.util.ColorLoggerUtils;
import org.csu.softwaremetrics_demo.util.FileUtils;
import org.csu.softwaremetrics_demo.util.result.DataResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;

/**
 * @Description:
 * @Author: Jukomu
 * @Package: org.csu.softwaremetrics_demo.controller
 * @Project: SoftwareMetrics_demo
 * @name: MetricController
 * @Date: 2025/4/5-20:08
 * @Filename: MetricController
 */
@RestController
@CrossOrigin
@RequestMapping("/metric")
public class MetricController {
    @Autowired
    private CKService ckService;
    @Autowired
    private LKService lkService;
    @Autowired
    private TraditionMetricService traditionMetricService;
    @Autowired
    private ClassDiagramMetricService classDiagramMetricService;
    @Autowired
    private UserCaseDiagramMetricService userCaseDiagramMetricService;

    private ColorLoggerUtils logger = new ColorLoggerUtils(MetricController.class);

    private String JAVA_CODE_BASE_PATH = "./src/main/resources/code/";
    private String DIAGRAM_BASE_PATH = "./src/main/resources/diagram/";

    /**
     * @param path
     * @return
     * @Description 使用Java代码进行度量
     */
    @RequestMapping("/code")
    public DataResult code(@RequestParam String path) {
        File file = new File(JAVA_CODE_BASE_PATH + path);
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        Object ckMetric = CKMetric(path).getDatas();
        Object lkMetric = LKMetric(path).getDatas();
        Object traditionMetric = TraditionMetric(path).getDatas();

        ArrayList<Object> allMetric = new ArrayList<>();
        allMetric.add(Map.of("CK", ckMetric));
        allMetric.add(Map.of("LK", lkMetric));
        allMetric.add(Map.of("Tradition", traditionMetric));

        return DataResult.successByDataArray(allMetric);
    }

    @RequestMapping("code/CKMetric")
    public DataResult CKMetric(@RequestParam("path") String path) {
        File file = new File((new File(JAVA_CODE_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        CKMetricResult ckMetricResult = ckService.calculate(file);
        // 将每个类的CK度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> CKMetricAllClass = new ArrayList<>();
        for (CKMetricSingleClass metric: ckMetricResult.all()) {
            if (metric.isError()) {
                continue;
            }
            CKMetricAllClass.add(metric.toMap());
        }
        return DataResult.successByDataArray(CKMetricAllClass);
    }

    @RequestMapping("code/LKMetric")
    public DataResult LKMetric(@RequestParam String path) {
        File file = new File((new File(JAVA_CODE_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        LKMetricResult lkMetricResult = lkService.calculate(file);
        // 将每个类的CK度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> LKMetricAllClass = new ArrayList<>();
        for (LKMetricSingleClass metric: lkMetricResult.all()) {
            if (metric.isError()) {
                continue;
            }
            LKMetricAllClass.add(metric.toMap());
        }
        return DataResult.successByDataArray(LKMetricAllClass);
    }

    @RequestMapping("code/TraditionMetric")
    public DataResult TraditionMetric(@RequestParam String path) {
        File file = new File((new File(JAVA_CODE_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        TraditionMetricResult traditionMetricResult = traditionMetricService.calculate(file);
        // 将每个类的CK度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> traditionMetricAllClass = new ArrayList<>();
        for (TraditionMetricSingleClass metric: traditionMetricResult.all()) {
            if (metric.isError()) {
                continue;
            }
            traditionMetricAllClass.add(metric.toMap());
        }
        return DataResult.successByDataArray(traditionMetricAllClass);
    }

    /**
     * @return
     * @Description 使用类图进行度量
     */
    @RequestMapping("/class-diagram")
    public DataResult classDiagram(@RequestParam String path) {
        File file = new File((new File(DIAGRAM_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        Object ckMetric = CKClassDiagram(path).getDatas();
        Object lkMetric = LKClassDiagram(path).getDatas();
        Object traditionMetric = TraditionClassDiagram(path).getDatas();

        ArrayList<Object> allMetric = new ArrayList<>();
        allMetric.add(Map.of("CK", ckMetric));
        allMetric.add(Map.of("LK", lkMetric));
        allMetric.add(Map.of("Tradition", traditionMetric));

        return DataResult.successByDataArray(allMetric);
    }

    @RequestMapping("/class-diagram/CKMetric")
    public DataResult CKClassDiagram(@RequestParam String path) {
        File file = new File((new File(DIAGRAM_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        CKMetricResult ckMetricResult = classDiagramMetricService.calculateCK(file);
        // 将每个类的CK度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> CKMetricAllClass = new ArrayList<>();
        for (CKMetricSingleClass metric: ckMetricResult.all()) {
            if (metric.isError()) {
                continue;
            }
            CKMetricAllClass.add(metric.toMap());
        }
        return DataResult.successByDataArray(CKMetricAllClass);
    }

    @RequestMapping("/class-diagram/LKMetric")
    public DataResult LKClassDiagram(@RequestParam String path) {
        File file = new File((new File(DIAGRAM_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        LKMetricResult lkMetricResult = classDiagramMetricService.calculateLK(file);
        // 将每个类的LK度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> LKMetricAllClass = new ArrayList<>();

        if (lkMetricResult == null) {
            logger.warn("No LK metric results for file: " + path);
            return DataResult.successByDataArray(LKMetricAllClass);
        }

        if (lkMetricResult.all() != null) {
            for (LKMetricSingleClass metric: lkMetricResult.all()) {
                if (metric != null && !metric.isError()) {
                    LKMetricAllClass.add(metric.toMap());
                }
            }
        }

        return DataResult.successByDataArray(LKMetricAllClass);
    }

    @RequestMapping("/class-diagram/TraditionMetric")
    public DataResult TraditionClassDiagram(@RequestParam String path) {
        File file = new File((new File(DIAGRAM_BASE_PATH).getAbsolutePath() + "/" + path));
        if (!file.exists()) {
            return DataResult.errByMessage("File not found");
        }
        TraditionMetricResult traditionMetricResult = classDiagramMetricService.calculateTradition(file);
        // 将每个类的传统度量结果转成Map，放进列表中
        ArrayList<Map<String, Object>> TraditionMetricAllClass = new ArrayList<>();

        if (traditionMetricResult == null) {
            logger.warn("No Tradition metric results for file: " + path);
            return DataResult.successByDataArray(TraditionMetricAllClass);
        }

        if (traditionMetricResult.all() != null) {
            for (TraditionMetricSingleClass metric: traditionMetricResult.all()) {
                if (metric != null && !metric.isError()) {
                    TraditionMetricAllClass.add(metric.toMap());
                }
            }
        }

        return DataResult.successByDataArray(TraditionMetricAllClass);
    }

    /**
     * @return
     * @Description 使用用例图进行度量
     */
//    @RequestMapping("usercase-diagram")
//    public DataResult usercaseDiagram(@RequestParam String path) {
//        File file = new File((new File(DIAGRAM_BASE_PATH).getAbsolutePath() + "/" + path));
//        if (!file.exists()) {
//            return DataResult.errByMessage("File not found");
//        }
//        return "Hello, Usercase Diagram Metrics!";
//    }

    /**
     * 上传文件接口
     * 根据传入的文件类型和文件数组，将文件保存到指定的路径，并返回上传成功的消息和唯一标识符
     *
     * @param files 要上传的文件数组
     * @param type 文件类型，用于确定文件保存的基础路径，"code"对应JAVA_CODE_BASE_PATH，其他对应DIAGRAM_BASE_PATH
     * @return 返回DataResult对象，包含上传成功消息和唯一标识符uuid
     */
    @PostMapping("/upload")
    public DataResult upload(@RequestParam("files") MultipartFile[] files, @RequestParam("type") String type) {
        // 记录日志，提示开始上传文件
        logger.info("上传文件");

        // 根据文件类型确定文件保存的基础路径
        String path = "code".equalsIgnoreCase(type) ? JAVA_CODE_BASE_PATH : DIAGRAM_BASE_PATH;

        // 生成一个唯一标识符
        String uuid = UUID.randomUUID().toString();

        // 将文件保存到指定路径
        // %s/%s/：第一个%s对应path，第二个%s对应uuid
        FileUtils.saveMultiFile(String.format("%s/%s/", path, uuid), files);

        // 返回上传成功消息和唯一标识符uuid
        return DataResult.successByMessage("上传成功", uuid);
    }

}
